#coding=utf-8
from __future__ import with_statement
from uliweb import expose
from uliweb.orm import get_model, do_, NotFound
from sqlalchemy.sql import or_, and_

def __begin__():
    from uliweb import function
    return function('require_login')()
    
@expose('/tasks/plan', restful=False)
class PlanView(object):
    def _get_defs(self, task, default=True):
        from uliweb import settings
        
        if task.task_type in settings.get_var('PARA/TASK_FREE_PLAN_TYPE'):
            defs = settings.get_var('PARA/SIMPLE_PLAN_DEFS')
        else:
            defs = settings.get_var('PARA/PLAN_DEFS')
        return [x for x in defs if x.get('default', 'True')==default]
    
    def edit(self, task_id):
        from uliweb.core import html
        
        task_id = int(task_id)
        
        TasksDevelop = get_model('tasks_develop')
        PlanEdit = get_model('planedit')
        Plan = get_model('plan')
        task = TasksDevelop.get(task_id)
        
        if not task.version_headerId:
            plan_objs = list(PlanEdit.filter(PlanEdit.c.task==int(task_id)))

#            count = PlanEdit.count(PlanEdit.c.task==int(task_id))
#            if not count:
#                plan_objs = []
#                #如果是主系统，则创建缺省的计划，如果不是，则为空，可以由系统自行创建自定义计划
#                #添加阶段
#                #todo: 对于计划有，但是编辑没有的情况要同步数据
#                for p in settings.get_var('PARA/PLAN_DEFS'):
#                    pe = PlanEdit(task=task, title=p['title'], type=p['type'], test_type=p.get('test_type', False),
#                        idn=p['idn'], is_public=True, is_reserved=True, main_sys=task._task_sys_, stage=p['stage'], weight=p.get('weight', 0))
#                    pe.save()
#                    plan_objs.append(pe)
#            else:
#                plan_objs = list(PlanEdit.filter(PlanEdit.c.task==int(task_id)))
        else:
            #查找PlanEdit中系统定义的保留计划,如果在Plan中不存在,则删除
            for x in PlanEdit.filter(PlanEdit.c.task==task.id).filter(PlanEdit.c.idn<5000):
                y = Plan.get((Plan.c.task==task.id) & (Plan.c.idn==x.idn))
                if not y:
                    x.delete()
                    
            PlanEdit.filter(PlanEdit.c.task==task.id).filter(PlanEdit.c.enabled==False).remove()
            condition = or_((PlanEdit.c.task==task._version_headerId_) & PlanEdit.systems.in_(task._task_sys_), 
                PlanEdit.c.task==task.id)
            plan_objs = list(PlanEdit.filter(condition))
       
        #将缺省计划与子计划进行合并,如果存在,说明已经建立,如果不存在,则自动
        #创建私有计划
        for p in self._get_defs(task):
            flag = False
            for po in plan_objs:
                if po.idn == p['idn']:
                    flag = True
                    break
            if not flag:
                pe = PlanEdit(task=task, title=p['title'], type=p['type'], test_type=p.get('test_type', False),
                    idn=p['idn'], is_public=False, is_reserved=not task.version_headerId, main_sys=task._task_sys_, stage=p['stage'], weight=p.get('weight', 0))
                pe.save()
                plan_objs.append(pe)
            
        def _cmp(x, y):
#            if x.end_date and y.end_date:
#                r = cmp(x.end_date, y.end_date)
#            elif not x.end_date and not y.end_date:
#                r = 0
#            elif not x.end_date and y.end_date:
#                r = -1
#            else:
#                r = 1
#            if r == 0:
#                return cmp(x.stage, y.stage)
#            return r
            r = cmp(x.stage, y.stage)
            if r == 0:
                return cmp(x.idn, y.idn)
            return r
        
        plan_objs.sort(_cmp)
        
        #添加阶段
        plan_tbody = t = html.Tag('tbody')
        with t:
            for row in plan_objs:
                t << self._show_plan_row(row, task_id)
        if request.user.users_systems.has(task._task_sys_) or request.user.is_gm or request.user.is_superuser:
            return {'task_type':'develop', 'plan_tbody':str(plan_tbody),
                'task_id':task_id}
        else:
            flash("你无权修改当前任务计划")
            return redirect('/tasks/develop/%s#plan' % task_id)
        
    def _show_plan_row(self, row, task_id):
        from uliweb.core.html import Tag
        from uliweb.utils.generic import make_view_field
        from uliweb.utils.common import get_choice
        from uliweb import settings
        
        #生成必须有效计划列表
        musts = {}
        for x in settings.get_var('PARA/PLAN_DEFS'):
            musts[x['idn']] = x.get('must', False)
            
        PlanEdit = get_model('planedit')
        
        if row.enabled:
            cls = 'enabled'
        else:
            cls = 'disabled'
        
        t = Tag('tr', id='plan_tr_%d' % row.id, _class=cls)
        with t:
            with t.td:
                if musts.get(row.idn):
                    t << '<img src="/static/plan/star.png" title="必选项">'
                else:
                    t << ''
            with t.td:
                if row.type == '1':
                    t << '<img src="/static/plan/plan.png" title="阶段">'
                else:
                    t << '<img src="/static/plan/milestone.png" title="里程碑">'
            with t.td:
                if row.enabled:
                    t << '<div class="ui-icon ui-icon-check"></div>'
                else:
                    t << '<div class="ui-icon ui-icon-closethick"></div>'
            with t.td:
                t << row.title
            with t.td:
                t << get_choice(settings.get_var('PARA/TASK_STAGE'), row.stage)
            with t.td:
                if row.is_public:
                    t << '<div class="ui-icon ui-icon-check"></div>'
                else:
                    t << '<div class="ui-icon ui-icon-closethick"></div>'
            if row.type == '1':
                with t.td:
                    t << row.get_display_value('begin_date')
            else:
                with t.td(style="background-color:#eee;", align="center"):
                    t << ''
            with t.td:
                t << row.get_display_value('end_date')
            with t.td:
                t << make_view_field(PlanEdit.main_sys, row)['display']
            with t.td:
                t << make_view_field(PlanEdit.systems, row)['display']
            with t.td:
                t << row.responsible
            with t.td:
                t << row.memo
            with t.td:
                if task_id != row._task_:   #说明是主系统计划，则不能修改
                    t << '主计划'
                else:
                    with t.a(href="javascript:void(0)", rel=row.id, _class='plan_edit'):
                        t << '编辑'
                    if not row.is_reserved:
                        with t.a(href="javascript:void(0)", rel=row.id, _class='plan_delete', onclick="return confirm('确定要删除当前记录吗？');"):
                            t << ' 删除'
        return str(t)
    
    def reset(self, task_id):
        PlanEdit = get_model('planedit')
        Plan = get_model('plan')
        
        PlanEdit.filter(PlanEdit.c.task==int(task_id)).remove()
        
        for p in Plan.filter(Plan.c.task==int(task_id)):
            d = p.to_dict(manytomany=True)
            d['enabled'] = True
            del d['id']
            pe = PlanEdit(**d)
            pe.save()
                
        return redirect(url_for(PlanView.edit, task_id=task_id))
    
    def change(self, plan_id):
        from uliweb.utils.generic import EditView
        from forms import PlanEditForm, MilestoneEditForm
        from uliweb.form.template_layout import TemplateLayout
        from functools import partial
        
        PlanEdit = get_model('planedit')
        plan = PlanEdit.get(int(plan_id))
        task_id = plan._task_
        
        def post_created_form(fcls, model, obj):
            fcls.layout_class = TemplateLayout
            if not obj.task.version_headerId:
                fcls.systems.query = obj.task.requirement.systems.all()
                if obj.type == '1':
                    if obj.is_reserved:
                        fcls.layout = 'layout_plan_reserved.html'
                    else:
                        fcls.layout = 'layout_plan_not_reserved.html'
                else:
                    if obj.is_reserved:
                        fcls.layout = 'layout_milestone_reserved.html'
                    else:
                        fcls.layout = 'layout_milestone_not_reserved.html'
            else:
                if obj.type == '1':
                    if obj.idn < '5000':
                        fcls.layout = 'layout_plan_reserved_private.html'
                    else:
                        fcls.layout = 'layout_plan_not_reserved_private.html'
                else:
                    if obj.idn < '5000':
                        fcls.layout = 'layout_milestone_reserved_private.html'
                    else:
                        fcls.layout = 'layout_milestone_not_reserved_private.html'
                
                
        def pre_save(obj, data):
            #如果是公共阶段，则
            if not data.get('is_public'):
                data['systems'] = [obj.task._task_sys_] 
                
        #如果是保留阶段，则某些字段不能修改，如：标题
        if plan.type == '1':
            if plan.is_reserved:
                fields = ['enabled', 'is_public', 'begin_date', 'end_date', 'systems', 'memo', 'responsible']
            else:
                if plan.idn < '5000':
                    fields = ['enabled', 'is_public', 'begin_date', 'end_date', 'systems', 'memo', 'responsible', 'test_type']
                else:
                    fields = ['stage', 'enabled', 'is_public', 'title', 'begin_date', 'end_date', 'systems', 'memo', 'responsible', 'test_type']
            form_cls = PlanEditForm
        else:
            if plan.is_reserved:
                fields = ['enabled', 'is_public', 'end_date', 'systems', 'memo', 'responsible']
            else:
                if plan.idn < '5000':
                    fields = ['enabled', 'is_public', 'end_date', 'systems', 'memo', 'responsible']
                else:
                    fields = ['stage', 'enabled', 'is_public', 'title', 'end_date', 'systems', 'memo', 'responsible']
            form_cls = MilestoneEditForm
            
        #如果是配合任务，则只能设置is_public = False
        if plan.task.version_headerId:
            fields.remove('is_public')
            fields.remove('systems')
            default_data = {'is_public':False}
        else:
            default_data = {}
            
        def success_data_handler(obj, task_id=task_id):
            d = {}
            d['data'] = self._show_plan_row(obj, task_id)
            d['id'] = obj.id
            return d
        
        view = EditView(PlanEdit, obj=plan, fields=fields, form_cls=form_cls,
            form_args={'action':request.path, 'html_attrs':{'id':'planedit_form'}},
            success_data=success_data_handler, post_created_form=post_created_form,
            pre_save=pre_save, data={'enabled':True}, default_data=default_data)
        view.form.task = plan.task
        view.form._check_plan_modified = self._check_plan_modified
        return view.run(json_result=True)
        
    def add(self, task_id):
        from uliweb.utils.generic import AddView
        from forms import PlanAddForm
        from uliweb.form.template_layout import TemplateLayout
        from sqlalchemy.sql import func
        from functools import partial
        from uliweb.form import SelectField
        
        task_id = int(task_id)
        
        PlanEdit = get_model('planedit')
        Task = get_model('tasks_develop')
        task = Task.get(task_id)
        
        def post_created_form(fcls, model):
            fcls.layout_class = TemplateLayout
            if not task.version_headerId:
               fcls.systems.query = task.requirement.systems.all()
               fcls.layout = 'layout_plan_add.html'
            else:
                fcls.layout = 'layout_plan_add_private.html'
            
        def pre_save(data):
            result = PlanEdit.filter((PlanEdit.c.task==task.id) & (PlanEdit.c.is_reserved==False)).values_one(func.max(PlanEdit.c.idn))[0]
            if result:
                data['idn'] = str(int(result)+1).zfill(4)
            else:
                data['idn'] = '5001'
            #如果是公共阶段，则
            if not data.get('is_public'):
                data['systems'] = [task._task_sys_]
        
        stage = SelectField('阶段分类', choices=settings.get_var('PARA/TASK_STAGE')[1:-1], required=True)
        
        def success_data_handler(obj, task_id=task_id):
            d = {}
            d['data'] = self._show_plan_row(obj, task_id)
            d['id'] = obj.id
            return d
        
        default_data={'is_reserved':False, 'task':int(task_id), 'main_sys':task._task_sys_}
        
        #如果是保留阶段，则某些字段不能修改，如：标题
        if not task.version_headerId:
            fields = (('stage', stage), 'enabled', 'type', 'is_public', 'title', 'begin_date', 'end_date', 'systems', 'memo', 'responsible', 'test_type')
        else:
            fields = (('stage', stage), 'enabled', 'type', 'title', 'begin_date', 'end_date', 'memo', 'responsible', 'test_type')
            default_data['is_public'] = False
        view = AddView(PlanEdit, fields=fields, form_cls=PlanAddForm,
            form_args={'action':request.path, 'html_attrs':{'id':'planedit_form'}},
            success_data=success_data_handler, post_created_form=post_created_form, pre_save=pre_save,
            default_data=default_data, data={'is_public':True, 'enabled':True})
        view.form.task = task
        return view.run(json_result=True)
    
    def delete(self, plan_id):
        from uliweb.utils.generic import DeleteView
        
        PlanEdit = get_model('planedit')
        plan = PlanEdit.get(int(plan_id))
        
        def validator(obj):
            Plan = get_model('plan')
            plan = Plan.get((Plan.c.idn==obj.idn) & (Plan.c.task==obj._task_))
            if plan:
                systems = self._check_plan_modified(plan)
                if systems:
                    msg = u'存在以下系统:%s已经执行了此计划，不能删除！' % ','.join(systems)
                    return msg.encode('utf-8')
            
        view = DeleteView('planedit', obj=plan, validator=validator)
        return view.run(json_result=True)
    
    def submit(self, task_id):
        from uliweb.orm import Rollback
        from uliweb.core.html import Tag
        from uliweb import settings
        from uliweb.core import dispatch
        
        task_id = int(task_id)
        PlanEdit = get_model('planedit')
        Plan = get_model('plan')
        Task = get_model('tasks_develop')
        plans = list(Plan.filter(Plan.c.task==task_id).order_by(Plan.c.idn))
        planedits = list(PlanEdit.filter(PlanEdit.c.task==task_id).order_by(PlanEdit.c.idn))
        
        task = Task.get(task_id)
        
        old_plan = Plan.get((Plan.c.task==task_id) & (Plan.c.idn=='1030'))
        if old_plan:
            old_version_date = old_plan.end_date
        else:
            old_version_date = None
        if old_plan:
            old_version_systems = old_plan.systems.ids()
        else:
            old_version_systems = []
        
        #生成必须有效计划列表
        musts = {}
        for x in self._get_defs(task):
            musts[x['idn']] = x.get('must', False)
        
        passed = True
        modified = False
        
        len_a = len(plans)
        len_b = len(planedits)
        
#        changes = {'add':[], 'delete':[], 'change':[]}
        table = Tag('table', border=0, _class='table')
        clone_fields = ['task', 'title', 'type', 'begin_date', 
            'end_date', 'test_type', 'memo', 'idn', 'main_sys', 'systems', 
            'is_public', 'is_reserved', 'stage', 'weight', 'responsible']
        check_fields = ['begin_date', 'end_date', 'systems', 'is_public', 
            'weight', 'memo', 'test_type', 'title', 'responsible', 'stage']
        key_fields = ['begin_date', 'end_date', 'systems']
        
        with table:
            with table.thead:
                with table.tr:
                    with table.th:
                        table << '检查项'
                    with table.th:
                        table << '变化'
                    with table.th:
                        table << '检查结果'
        
            x = y = 0
            
            def must(table, b):
                with table.tr:
                    with table.td:
                        table << b.title
                    with table.td:
                        table << '必选项'
                    with table.td:
                        table << '未通过...'
                return False, False        
                
            def add(table, b):
                with table.tr:
                    with table.td:
                        table << b.title
                    with table.td:
                        table << '新增'
                    with table.td:
                        table << '通过...'
#                changes['add'].append(b.to_dict(manytomany=True))
                values = b.to_dict(fields=clone_fields, manytomany=True)
                row = Plan(**values)
                row.save()
                row.systems.update(*values['systems'])
                #记录修改情况
                self._record_add(row, values)
                #同步增加PlanExecute
                self._planexecute_add(row)
                return True, True        
            
            def delete(table, a):
                passed = True
                modified = False
                with table.tr:
                    with table.td:
                        table << a.title
                    with table.td:
                        table << '删除'
                    with table.td:
                        systems = self._check_plan_modified(a)
                        if systems:
                            passed = False
                            table << u'在检查[%s]计划删除时，存在以下系统%s已经修改了此计划实际开始或结束时间' % (a.title, ','.join(systems))
                        else:
                            modified = True
                            table << '通过...'
#                changes['delete'].append(a.to_dict(manytomany=True))
                if modified:
                    #同步删除PlanExecute
                    self._planexecute_delete(a)
                    #记录删除信息
                    self._record_delete(a)
                    a.delete()
                return passed, modified
                
            def change(table, a, b):
                va = a.to_dict(fields=check_fields, manytomany=True)
                vb = b.to_dict(fields=check_fields, manytomany=True)
                passed = True
                modified = False
                with table.tr:
                    with table.td:
                        table << a.title
                    with table.td:
                        table << '修改'
                    with table.td:
                        if va != vb:
                            _a = a.to_dict(fields=key_fields, manytomany=True)
                            _b = b.to_dict(fields=key_fields, manytomany=True)
                            if _a != _b:
                                msg = self._check_plan(a, b, va, vb)
                                if msg:
                                    passed = False  #未通过
                                    table << msg
                                    return passed, modified
                            modified = True
                            table << '通过...'
                        else:
                            table << '无变化...'
                if modified:
                    values_a = a.to_dict(manytomany=True)
                    values_b = b.to_dict(manytomany=True)
                    self._record_change(a, values_a, values_b)
                    values = b.to_dict(fields=clone_fields, manytomany=True)
                    a.update(**values)
                    a.save()
                    #同步更新PlanExecute
                    self._planexecute_change(a, values_a['systems'], values_b['systems'])
                    
                return passed, modified
            
            with table.tbody:
                while x<len_a and y<len_b:
                    a = plans[x]
                    b = planedits[y]
                    #如果有效未设，但是是必须项，则提示修改
                    if not b.enabled:
                        if musts.get(b.idn):
                            if not task._version_headerId_:
                                r = must(table, b)
                                passed &= r[0]
                                modified |= r[1]
                        y += 1
                    #idn相同表示不是新增或删除，则比较是否内容发生了变化，内容不对备注进行比较
                    elif a.idn == b.idn:
                        r = change(table, a, b)
                        passed &= r[0]
                        modified |= r[1]
                        x += 1
                        y += 1
                    #以下判断说明新增了计划，直接通过
                    elif a.idn > b.idn:
                        r = add(table, b)
                        passed &= r[0]
                        modified |= r[1]
                        y += 1
                    #说明计划有删除，检查是否存在问题
                    else:
                        r = delete(table, a)
                        passed &= r[0]
                        modified |= r[1]
                        x += 1
                  
                #说明还存在将要删除的计划
                if x < len_a:
                    for i in range(x, len_a):
                        r = delete(table, plans[i])
                        passed &= r[0]
                        modified |= r[1]
                        
                #说明还存在将要新增或待检查是否必输项的计划
                if y < len_b:
                    for i in range(y, len_b):
                        b = planedits[i]
                        if not b.enabled:
                            if musts.get(b.idn):
                                r = must(table, b)
                                passed &= r[0]
                                modified |= r[1]
                        else:
                            r = add(table, b)
                            passed &= r[0]
                            modified |= r[1]
        
        if not modified or not passed:
#            self._save_changed(changes, task_id)
#        else:
            Rollback()
        else:
            #同步投产时间
            plan = Plan.get((Plan.c.task==task_id) & (Plan.c.idn=='1030'))
            if plan:
                if not old_version_date or old_version_date != plan.end_date or set(old_version_systems) != set(plan.systems.ids()):
                    #如果是主任务，则将主任务，包括配合任务全部改掉，注意只改
                    #相关执行系统的任务，非执行系统的不改
                    plan.task.version_date = plan.end_date
                    plan.task.save()
                    if not plan.task._version_headerId_:
                        #如果是主任务，则将所有执行系统的子任务找出，并修改
                        for task in Task.filter(and_(Task.c.version_headerId==plan._task_,
                                Task.c.task_sys.in_(plan.systems.ids())
                            )):
                            task.version_date = plan.end_date
                            task.save()
        
            #发出task_change topic
            dispatch.call(Task, 'task_change', instance=task, created=False, data={}, old_data={})
            
        return {'pre_submit':str(table), 'passed':passed, 'modified':modified, 'task_id':task_id}
    
    def _record_add(self, plan, data):
        """
        记录计划增加变化
        """
        import pickle

        PlanChange = get_model('planchange')
        changed_value = pickle.dumps(data, pickle.HIGHEST_PROTOCOL)
        c = PlanChange(task_id=plan._task_, plan_id=plan.id, modify_flag='1', 
            old_value='', changed_value=changed_value, idn=plan.idn, weight=plan.weight)
        c.save()
        
    def _record_delete(self, plan):
        import pickle
        
        PlanChange = get_model('planchange')
        old_value = pickle.dumps(plan.to_dict(manytomany=True), pickle.HIGHEST_PROTOCOL)
        c = PlanChange(task_id=plan._task_, plan_id=plan.id, modify_flag='3', 
            old_value=old_value, changed_value='', idn=plan.idn, weight=plan.weight)
        c.save()
        
    def _record_change(self, plan, valuea, valueb):
        import pickle
        
        PlanChange = get_model('planchange')
        old_value = pickle.dumps(valuea, pickle.HIGHEST_PROTOCOL)
        changed_value = pickle.dumps(valueb, pickle.HIGHEST_PROTOCOL)
        c = PlanChange(task_id=plan._task_, plan_id=plan.id, modify_flag='2', 
            old_value=old_value, changed_value=changed_value, idn=plan.idn, weight=plan.weight)
        c.save()

#    def _save_changed(self, changes, task_id):
#        import pickle
#        
#        PlanChange = get_model('planchange')
#        changed_value = pickle.dumps(changes, pickle.HIGHEST_PROTOCOL)
#        row = PlanChange(task=task_id, changed_value=changed_value)
#        row.save()
#        
    def _planexecute_add(self, plan):
        """
        同步增加PlanExecute
        """
        PlanExecute = get_model('planexecute')
        
        #增加主任务计划，要判断systems中是否有当前system
        if plan.systems.has(plan.task._task_sys_):
            e = PlanExecute(task=plan._task_, plan=plan.id, system=plan.task._task_sys_, type=plan.type)
            e.save()
        
        #保存子任务
        for t in plan.task.child_tasks.all():
            if plan.systems.has(t.task_sys):
                pe = PlanExecute(task=t.id, plan=plan.id, type=plan.type, system=t._task_sys_)
                pe.save()
        
    def _planexecute_delete(self, plan):
        """
        同步删除PlanExecute
        """
        PlanExecute = get_model('planexecute')
        PlanDetails = get_model('planexecutedetails')

        PlanDetails.remove(PlanDetails.c.plan==plan.id)
        PlanExecute.remove(PlanExecute.c.plan==plan.id)
        
    def _planexecute_change(self, plan, systems_old, systems_new):
        """
        同步修改PlanExecute
        """
        PlanExecute = get_model('planexecute')
        PlanDetails = get_model('planexecutedetails')

        #旧的多的，要删除
        diffa = set(systems_old) - set(systems_new)
        if diffa:
            PlanExecute.remove((PlanExecute.c.plan==plan.id) & PlanExecute.c.system.in_(diffa))
            PlanDetails.remove((PlanDetails.c.plan==plan.id) & PlanDetails.c.system.in_(diffa))
        #新的多的，要增加
        diffb = set(systems_new) - set(systems_old)
        if diffb:
            if plan.task._task_sys_ in diffb:
                pe = PlanExecute(task=plan._task_, plan=plan.id, type=plan.type, system=plan.task._task_sys_)
                pe.save()
                
            for t in plan.task.child_tasks.all():
                if t._task_sys_ in diffb:
                    pe = PlanExecute(task=t.id, plan=plan.id, type=plan.type, system=t._task_sys_)
                    pe.save()
        
    def _check_plan(self, old, new, old_value, new_value):
        #如果将公共改为私有，则要检查是否已经存在对应的系统有的已经填报了计划，如果有，则进行提示
        #检查内容：
        #开始时间
        if old.is_public != new.is_public and old.is_public:
            systems = self._check_plan_modified(old)
            if systems:
                return u'存在以下系统:%s已经修改了此计划实际开始或结束时间' % ','.join(systems)
        if old_value['systems'] != new_value['systems']:
            diff = set(old_value['systems']) - set(new_value['systems'])
            systems = self._check_plan_modified(old, diff)
            if systems:
                return u'存在以下系统:%s已经修改了此计划实际开始或结束时间' % ','.join(systems)
            
    def _check_plan_modified(self, plan, systems=None):
        P = get_model('planexecute')
        
        condition = (P.c.plan==plan.id) & (~(P.c.finish_begin_date==None) | ~(P.c.finish_end_date==None))
        if systems is not None:
            if systems:
                condition = condition & P.c.system.in_(systems)
            else:
                return []
        
        r = P.filter(condition)
        systems = []
        for x in r:
            systems.append(x.system.abbr)
        return systems
    
    def view(self, task_id):
        from uliweb.core.html import Buf
        
        task_id = int(task_id)
        Plan = get_model('plan')
        Task = get_model('tasks_develop')
        task = Task.get_or_notfound(task_id)
        
        plan_objs = list(Plan.filter(Plan.c.task==int(task_id)))
        #如果存在主任务，则同时将主任务的计划取出来，同时显示，但是不能编辑
        if task._version_headerId_:
            plan_objs = list(Plan.filter(Plan.c.task==task._version_headerId_).filter(Plan.systems.in_(task._task_sys_))) + plan_objs
        
        def _cmp(x, y):
            r = cmp(x.stage, y.stage)
            if r == 0:
                return cmp(x.end_date, y.end_date)
            return r
        
        plan_objs.sort(_cmp)
        
        t = Buf()
        with t.tbody:
            for row in plan_objs:
                t << self._show_plan(row, task_id)
        
        return str(t)

    def _get_cur_week_date(self):
        from datetime import date, timedelta
        
        today = date.today()
        begin = today - timedelta(days=(today.weekday()+2)%7)
        end = begin + timedelta(days=6)
        return begin, end
    
    def _show_plan(self, row, task_id):
        from uliweb.core.html import Tag, Buf
        from uliweb.utils.generic import make_view_field
        from uliweb.utils.common import get_choice, date_in
        from uliweb import settings
        from datetime import date
        
        #生成必须有效计划列表
        musts = {}
        for x in settings.get_var('PARA/PLAN_DEFS'):
            musts[x['idn']] = x.get('must', False)
        
        Plan = get_model('plan')
        PlanExecute = get_model('planexecute')
        Task = get_model('tasks_develop')
        TestPlan = get_model('testplan')
        task = Task.get(task_id)
        e = PlanExecute.get((PlanExecute.c.task==task_id) & (PlanExecute.c.plan==row.id) & (PlanExecute.c.system==task._task_sys_))
        #if e为空说明非本系统的计划执行
        WE = get_model('planexecutedetails')
        
        cur = None
        today = date.today()
        if row.begin_date and row.end_date and row.begin_date <= today <= row.end_date:
            cur = True
        elif row.end_date:
            if today == row.end_date:
                cur = True
        
        if cur:
            cls = 'parent current-plan'
        else:
            cls = 'parent'
            
        #查找本周情况信息，需要对本系统计划进行处理
        begin, end = self._get_cur_week_date()
        is_mine = row.systems.has(task._task_sys_)
        if is_mine:
            we = WE.get((WE.c.begin_date==begin) & (WE.c.end_date==end) & (WE.c.planexecute==e.id))
            if not we:
                we = WE(begin_date=begin, end_date=end, task=task.id, plan=row.id, 
                    system=task._task_sys_, planexecute=e.id)
                we.save()
        else:
            we = None 
         
        #是否本周计划
        today = date.today()
        flag = False
        if row.type == '1' and ((row.begin_date <= today <= row.end_date) or 
            date_in(today, [row.begin_date, row.end_date]) or 
            date_in(row.begin_date, [begin, end]) or 
            date_in(row.end_date, [begin, end]) or 
            (e and e.finish_begin_date and e.finish_end_date and not (e.finish_end_date < begin or e.finish_begin_date > end)) or
            (e and e.finish_begin_date and not e.finish_end_date and e.finish_begin_date <= end)
            ):
            flag = True
        elif row.type == '2' and (date_in(row.end_date, [begin, end]) or (e and date_in(e.finish_end_date, [begin, end]))):
            flag = True

        buf = Buf()
        t = Tag('tr', id='plan_tr_%d' % row.id, _class=cls)
        with t:
            with t.td(align='center'):
                t << '<img class="expand" src="/static/plan/plus.gif" style="cursor:pointer"/>'
            with t.td(align='center'):
                if row.type == '1':
                    t << '<span class="milestone">阶段</span>'
                else:
                    t << '<span class="plan">里程碑</span>'
            with t.td:
                if row.is_public:
                    t <<'<img src="/static/plan/open.png" title="公共计划"/>'
                else:
                    t <<'<img src="/static/plan/closed.png" title="私有计划"/>'
                if row.systems.has(task._task_sys_):
                    t <<'<img src="/static/plan/hammer.png" title="需要执行的计划"/>'
                else:
                    t <<'<img src="/static/plan/eye.png" title="只能查看的计划"/>'
                t << row.title
            with t.td(align='center'):
                if e and row.test_type:
                    #如果是测试类型，则显示测试计划相关的信息
                    try:
                        e.testplan
                    except NotFound:
                        e.testplan = None
                        e.save()
                    if e._testplan_:
                        if e.testplan.approve != '1':
                            t << '<a href="/tests/plans/view/%d">%s</a>' % (e.testplan.id, e.testplan.get_display_value('approve'))
                        else:
                            t << '<a href="/tests/plans/view/%d">%s</a>' % (e.testplan.id, e.testplan.test_id)
                    else:
                        #当前用户可以维护系统，并且是主任务才可以提交测试计划审请
                        if e.task.task_sys.users.has(request.user) and e._task_ == row._task_:
                            t << '<a href="/tests/plans/assign?planexecute=%d">提交申请</a>' % e.id
                        else:
                            t << '尚未提交'
                else:
                    t << '-'
            if row.memo:
                comment = str(Tag('img', None, src='/static/plan/comment.png', title=row.memo))
            else:
                comment = ''
            if row.type == '1':
                with t.td(align='center'):
                    t << str(row.get_display_value('begin_date')) + ' - ' + str(row.get_display_value('end_date')) + comment
            else:
                with t.td(align='center'):
                    t << str(row.get_display_value('end_date')) + comment
            if e:
                if e.memo:
                    comment = str(Tag('img', None, src='/static/plan/comment.png', title=e.memo))
                else:
                    comment = ''
                if row.type == '1':
                    with t.td(align='center'):
                        t << (str(e.get_display_value('finish_begin_date')) or '未完成') + ' - ' + (str(e.get_display_value('finish_end_date')) or '未完成') + comment
                else:
                    with t.td(align='center'):
                        t << (str(e.get_display_value('finish_end_date')) or '未完成') + comment
            else:
                with t.td(align='center'):
                    t << ''
            with t.td(align='center'):
                if e:
                    if e.status == '2':
                        #如果延迟，则显示为特殊样式
                        t << '<div class="delay">%s</div>' % make_view_field(PlanExecute.status, e)['display']
                    else:
                        t << make_view_field(PlanExecute.status, e)['display']
                else:
                    t << ''
            with t.td(align='center'):
                if flag and is_mine:
                    if we.desc:
                        t << '<span class="info">已填写</span>'
                    else:
                        t << '<span class="info">未填写</span>'
                else:
                    t << '&nbsp';
            with t.td:
                if request.user.users_systems.has(task._task_sys_) and is_mine:
                    if task.stage != 'FN':
                        with t.a(href="javascript:void(0)", rel=row.id, _class='edit'):
                            t << '更新'
                        if row.type == '1':
                            with t.a(href="javascript:void(0)", rel=row.id, _class='add_work'):
                                t << '报工'
                    else:
                        with t.a(href="javascript:void(0)", rel=row.id, _class='add_work'):
                            t << '报工'
                    #添加，当计划在周报范围内时，填写本周完成情况
                    if flag:
                        with t.a(href="javascript:void(0)", rel=e.id, _class='week_execute'):
                            t << '本周执行'
                else:
                    if task._kfzx_ == request.user._kfzx_ and request.user.is_gm and is_mine:
                        #如果是任务所对应的开发中心的主管，则可以更新，以防止计划结束无法编辑的情况
                        with t.a(href="javascript:void(0)", rel=row.id, _class='edit'):
                            t << '更新'
                    else:
                        t << '&nbsp;'
        buf << t
        cls = 'child'
        t = Tag('tr', id='plan_tr_%d_child' % row.id, _class=cls, style='display:none')
        with t:
            with t.td:
                t << '&nbsp;'
            with t.td(colspan=8):
                with t.div:
                    t << '<b>阶段分类：</b>' + get_choice(settings.get_var('PARA/TASK_STAGE'), row.stage)
                    t << ' | <b>计划系统：</b>' + make_view_field(Plan.main_sys, row)['display']
                    t << ' | <b>责任人：</b>' + row.responsible.encode('utf-8')
                    t << ' | <b>执行系统：</b>' + make_view_field(Plan.systems, row)['display']
                if is_mine:
                    with t.div:
                        t << '<b>本周执行内容：</b><span class="week_desc">%s</span>' % make_view_field(WE.desc, we)['display']
                    with t.div:
                        t << '<b>实际完成进度：</b><span class="week_finish">%.1f%%</span>' % (we.finish * 100)
                        t << ' | <b>执行人：</b><span class="week_executer">%s</span>' % make_view_field(WE.executer, we)['display']
                        if we.desc:
                            d = make_view_field(WE.modified_date, we)['display']
                        else:
                            d = ''
                        t << ' | <b>填写时间：</b><span class="week_syncdate">%s</span>' % d
        buf << t
        return str(buf)

    def add_week(self, planexecute_id):
        """
        本周工作情况录入
        """
        from uliweb.utils.generic import EditView
        from forms import PlanExecuteDetailsForm
        from datetime import date
        
        WE = get_model('planexecutedetails')
        PlanExecute = get_model('planexecute')
        
        pe = PlanExecute.get(int(planexecute_id))
        begin, end = self._get_cur_week_date()
        we = WE.get((WE.c.begin_date==begin) & (WE.c.end_date==end) & (WE.c.planexecute==pe.id))
        if not we:
            we = WE(begin_date=begin, end_date=end, task=pe._task_, plan=pe._plan_, 
                system=pe.task._task_sys_, finish=pe.finish, executer=pe.executer,
                planexecute=pe.id)
            we.save()
            
        def post_created_form(fcls, model, obj):
            fcls.desc.required = True
            fcls.executer.required = True
            fcls.finish.required = True
            
        def post_save(obj, data):
            pe.desc = obj.desc
            pe.finish = obj.finish or pe.finish
            pe.executer = obj.executer
            pe.sync_date = date.today()
            pe.save()
        
        def _success_change_plan_handler(obj):
            from uliweb.utils.textconvert import text2html

            desc = text2html(obj.field_str(obj.desc))
            return {'id':obj._plan_, 'desc':desc, 'finish':'%.0f%%' % (obj.finish * 100), 
                'executer':obj.executer, 'info':bool(obj.desc),
                'syncdate':obj.modified_date}
            
        view = EditView(WE, obj=we, 
            form_args={'action':request.path, 'html_attrs':{'id':'add_week_form'}}, 
            success_data=_success_change_plan_handler, post_save=post_save,
            post_created_form=post_created_form, form_cls=PlanExecuteDetailsForm)
        return view.run(json_result=True)
        
    def add_work(self, task_id, plan_id):
        """
        报工的处理
        """
        from uliweb.utils.generic import AddView
        from uliweb.form import BooleanField
        from uliweb.form.template_layout import TemplateLayout
        
        Plan = get_model('plan')
        PlanExecute = get_model('planexecute')
        Task = get_model('tasks_develop')
        
        task = Task.get(int(task_id))
        plan = Plan.get(int(plan_id))
        e = PlanExecute.get((PlanExecute.c.task==task.id) & (PlanExecute.c.plan==plan.id) & (PlanExecute.c.system==task._task_sys_))
        
        set_begin_date = BooleanField('设置开始完成时间')
        set_end_date = BooleanField('设置结束完成时间')
        fields = ('begin_time', 'end_time', 'amount_inner_input', 'amount_outer_input', 
            'amount_inner_design', 'amount_outer_design', 'amount_inner_out8', 
            'amount_outer_out8', 'amount_inner_weekend', 'amount_outer_weekend',
            'memo', ('set_end_date', set_end_date), ('set_begin_date', set_begin_date))
            
        data = {}
        data['task_id'] = task.task_id
        data['requirement'] = task._requirement_
        data['task_sys'] = task._task_sys_
        data['kfzx'] = task._kfzx_
        data['tx'] = task._tx_
        data['task_type'] = task.task_type
        data['assignment'] = task._assignment_
        data['stage'] = plan.stage
        data['rel_sys'] = task._rel_sys_
        data['plan'] = plan.id
        
        def post_created_form(fcls, model):
            fcls.layout_class = TemplateLayout
            fcls.layout = 'layout_plan_add_work.html'
            
        def pre_save(data):
            data['year'] = data['begin_time'].year
            data['month'] = data['begin_time'].month
            data['year_month'] = data['year']*100 + data['month']
        
        def post_save(o, data):
            modified = False
#            if not e:
#                e = PlanExecute(task=task.id, plan=plan.id, system=task._task_sys_, type=plan.type)
#                modified = True
#            if (e.finish_begin_date and e.finish_begin_date > data['begin_time']) or not e.finish_begin_date:
#                e.finish_begin_date = data['begin_time']
#                modified = True
            if data.get('set_begin_date'):
                e.finish_begin_date = data['begin_time']
                modified = True
            if data.get('set_end_date'):
                e.finish_end_date = data['end_time']
                modified = True
    
            if modified:
                e.save()
                
            #更新主记录工作量
            task.amount_inner_input += data.get('amount_inner_input', 0)
            task.amount_outer_input += data.get('amount_outer_input', 0)
            task.amount_inner_design += data.get('amount_inner_design', 0)
            task.amount_outer_design += data.get('amount_outer_design', 0)
            task.amount_inner_out8 += data.get('amount_inner_out8', 0)
            task.amount_outer_out8 += data.get('amount_outer_out8', 0)
            task.amount_inner_weekend += data.get('amount_inner_weekend', 0)
            task.amount_outer_weekend += data.get('amount_outer_weekend', 0)
            task.save()
            
        from forms import AddWorkForm
        view = AddView('tasks_details', '/tasks/develop/%d#plan' % task.id, fields=fields, form_cls=AddWorkForm,
            form_args={'action':request.path, 'html_attrs':{'id':'add_work_form'}},
            default_data=data, post_save=post_save, post_created_form=post_created_form,
            template_data={'task_type':'develop'}, pre_save=pre_save)
        view.form.plan = plan
        view.form.pe = e
        return view.run(json_result=True)
    
    def _get_plan_status(self, obj, data):
        """
        根据计划的执行获得计划的执行状态
        """
        from datetime import date
        
        today = date.today()
        
        def _get_status(date, plan_date):
            if date:
                if date < plan_date:
                    status = '6'    #提前
                elif date == plan_date:
                    status = '3'    #完成
                else:
                    status = '7'    #延迟
            else:
                if plan_date < today:
                    status = '2'
                else:
                    status = '1'
            return status
        
        if obj.type == '1':
            #阶段
            if data['finish_end_date'] or obj.plan.end_date < today:
                status = _get_status(data['finish_end_date'], obj.plan.end_date)
                if status == '7':
                    #如果延迟完成，对于开始完成时间，设置为延迟
                    status = '3'
            else:
                status = _get_status(data['finish_begin_date'], obj.plan.begin_date)
                if status == '7':
                    #如果延迟完成，对于开始完成时间，设置为延迟
                    status = '2'
                if status == '3':
                    status = '1'
        else:
            status = _get_status(data['finish_end_date'], obj.plan.end_date)
            if status == '7':
                #如果延迟完成，对于结束完成时间，设置为完成
                status = '3'
        return status
        
    def change_plan(self, task_id, plan_id):
        """
        填报计划完成时间
        """
        from uliweb.utils.generic import EditView
        from forms import PlanExecuteEditForm

        Plan = get_model('plan')
        PlanExecute = get_model('planexecute')
        Task = get_model('tasks_develop')
        TestPlan = get_model('testplan')
        
        plan = Plan.get(int(plan_id))
        task = Task.get(int(task_id))
        pe = PlanExecute.get((PlanExecute.c.task==task.id) & (PlanExecute.c.plan==plan.id))
        if not pe:
            pe = PlanExecute(task=task.id, plan=plan.id, system=task._task_sys_, type=plan.type)
            pe.save()
            
        def pre_save(obj, data):
            data['status'] = self._get_plan_status(obj, data)
            
        def post_save(obj, data):
            from uliweb.core import dispatch
            
            if obj.plan.idn == '1090':   #如果是结束时间里程碑，则自动修改主记录为完成阶段
                #如果填充了完成时间，则置相应的任务状态为完成
                if data.get('finish_end_date'):
                    task.stage = 'FN'
                    task.status = '1'   #update 修改完成阶段的同时，修改状态为正常
                    task.save()
                else:
                #如果完成时间为空，则将任务状态修改为上一个阶段的状态，不过这句不一定可以执行
                #因为，任务一旦完成，将不可修改
                    query = self._get_plan(task).filter(Plan.c.type=='1')
                    if query.count() > 0:
                        p = query.order_by(Plan.c.end_date.desc()).one()
                        task.stage = p.stage
                        task.save()
                        
                #添加一个任务完成的信号
                dispatch.call(None, 'task_develop_finished', task=task, finish_date=data.get('finish_end_date'))
                
            #同步修改测试计划，同时修改测试状态
            #todo 待处理
#            testplan = pe.planexecute_plans.all().one()
#            if testplan:
#                testplan.real_begin_date = data.get('finish_begin_date')
#                #如果填写了开始时间，但是测试执行状态为未开始，则改为进行中
#                if data.get('finish_begin_date') and testplan.status == '1':
#                    testplan.status = '2'
#                testplan.real_end_date = data.get('finish_end_date')
#                #如果填写了完成时间，但是测试执行状态为进行中，则改为完成
#                if data.get('finish_end_date') and testplan.status == '2':
#                    testplan.status = 'F'
#                testplan.save()
                
        if pe.type == '1':
            fields = ('finish_begin_date', 'finish_end_date', 'memo')
        else:
            fields = ('finish_end_date', 'memo')
            
        def _success_change_plan_handler(data, e=pe):
            from uliweb.core.html import Tag
            
            if e.memo:
                comment = str(Tag('img', None, src='/static/plan/comment.png', title=e.memo))
            else:
                comment = ''
            if e.type == '1':
                txt = str(e.get_display_value('finish_begin_date')) + ' - ' + str(e.get_display_value('finish_end_date')) + comment
            else:
                txt = str(e.get_display_value('finish_end_date')) + comment
            if e.status == '2':
                status = '<div class="delay">延迟</div>'
            else:
                status = e.get_display_value('status').encode('utf-8')
            r =  {'data':txt, 'id':pe.plan.id, 'status':status}
            return r
        
        view = EditView(PlanExecute, obj=pe, fields=fields, form_cls=PlanExecuteEditForm,
            form_args={'action':request.path, 'html_attrs':{'id':'planedit_form'}}, 
            success_data=_success_change_plan_handler, post_save=post_save,
            pre_save=pre_save)
        return view.run(json_result=True)

    def _get_plan(self, task):
        """
        获得某个任务对应的所有计划，如果是子任务还包括主计划
        """
        Plan = get_model('plan')
        
        if not task._version_headerId_:
            plan_objs = Plan.filter(Plan.c.task==task.id)
        else:
            condition = or_((Plan.c.task==task._version_headerId_) & Plan.systems.in_(task._task_sys_), 
                Plan.c.task==task.id)
            plan_objs = Plan.filter(condition)
            
        return plan_objs
        